﻿using System;
using System.Collections.Generic;


namespace FinQ
{

    /// <summary>
    /// Sam's functional programming library. F'LINQ!
    /// </summary>
    static partial class Functional
    {
        // O(n) count! could improve by container type specialization
        public static int Count<T>(this IEnumerable<T> seq)
        {
            return Reduce(seq, 0, (x, y) => y + 1);
        }

        // sum
        public static double Sum(this IEnumerable<double> seq)
        {
            return Reduce(seq, 0D, (x, y) => x + y);
        }

        // arithmetic mean
        public static double Avg(this IEnumerable<double> seq)
        {
            return seq.Sum() / seq.Count();
        }

        // min
        public static double Min(this IEnumerable<double> seq)
        {
            return Reduce(seq, double.MaxValue, (x, y) => (x < y) ? x : y);
        }

        // max
        public static double Max(this IEnumerable<double> seq)
        {
            return Reduce(seq, double.MinValue, (x, y) => (x > y) ? x : y);
        }


        // variance (of population by default)
        public static double Variance(this IEnumerable<double> seq)
        {
            return VarP(seq);
        }

        // variance of population - VarP
        public static double VarP(this IEnumerable<double> seq)
        {
            double avg = seq.Avg();
            return Map(seq, x => Square(x - avg)).Avg();
        }
        
        // variance of sample - VarA
        public static double VarA(this IEnumerable<double> seq)
        {
            double avg = seq.Avg();
            int count = seq.Count();
            if (count < 1) return 0;
            return Map(seq, x => Square(x - avg)).Sum() / (count - 1);
        }


        // standard deviation (of population by default)
        public static double StdDev(this IEnumerable<double> seq)
        {
            return StdDevP(seq);
        }

        // standard deviation (of population)
        public static double StdDevP(this IEnumerable<double> seq)
        {
            return Math.Sqrt(VarP(seq));
        }

        // standard deviation (of sample)
        public static double StdDevA(this IEnumerable<double> seq)
        {
            return Math.Sqrt(VarA(seq));
        }
        
    }
}
